#include "DiskSector.h"
using namespace std;
/**
 * 磁盘扇区操作类 
 */
class DiskSector {
public:
    int fd;
    int sectorsize;
    long postion;
    long size;
    char *mallocMem;
    char *dev;
    bool debug;  //调试信息  
    DiskSector(const char *dev){
        this->debug=false;
        this->dev=(char *)dev;
        fd = open(dev, O_RDONLY);
        if (fd == -1)   throw new Exception("open dev failed \n");
        sectorsize=512;
        mallocMem=NULL;
        size=0;
        postion=0;
    }
   ~DiskSector (){
        close(fd);
    }
   
    char *get(unsigned long sector,int len=1) {
        if(this->debug) printf("Desk sector read postion: %lu,len: %d\n",sector,len);
        this->postion = sector;
//        if(sector >255883256) {
//            int a=1;
//            throw new Exception("to postion failed!!! \n",-1);
//        }
        //重复读取一个扇区做缓存处理
        static unsigned long _sector;
        static int _len;
        if(_sector == sector && len==_len) return mallocMem; 
        _sector = sector; _len==len; 
        
        char *p;
        /* seek it */
        lseek(fd, 0, SEEK_SET);
        if (lseek(fd, (sectorsize * sector), SEEK_CUR) == -1) {
//            printf("Err: goto postion:%ld  failed \n",this->postion);
            throw new Exception("goto postion  failed\n",-1);
        }
        
        /* read it */
        p = (char *) malloc(sectorsize*len);
        if (p == NULL)     throw new Exception("malloc memory failed\n",-1);    
        
         read(fd, p, sectorsize*len);
         
         if (p == NULL) throw new Exception("read failed\n",-1);
         
         if(mallocMem!=NULL) free(mallocMem);
         mallocMem=p;
         return p;
    }

    /* dump data for display */
    void dump(char *p,int size=0 ) {
        int i;
        char str[20];  
        memset(str,0,sizeof(str));
        if(size==0) size=this->sectorsize;
        int line=1;
        printf(" 0  1  2  3  4  5  6  7    8  9  A  B  C  D  E  F \n");
        for (i = 0; i < size; i++) {
            if (i % 16 == 0 && i != 0)  { 
                printf("\t|%s|\n",str);
                str[0]='\0';
            }
            if (i % 16 == 8)  printf("  ");
            
            str[i%16]= isprint(p[0])?  p[0] :  '.' ;
            printf("%2.2x ", /* (unsigned int) p & 0xff*/(unsigned char)*p++);
        }
        
        printf("\t|%s|\n",str);
        return;
    }
    
    string getHexStr(char *p,int size=0){
           int i;
           string str;
           char element[10];
           if(size==0) size=this->sectorsize;
           for (i = 0; i < size; i++) {
               sprintf(element,"%2.2x", /* (unsigned int) p & 0xff*/(unsigned char)*p++);
               str.append(element);
        }
           
        return str;
    }
    
    string getSize(long p,char t='0'){
        string size;
        long sizeK=p/2;
        ostringstream os;  
         switch(t) {
            case  'G':
                  os<<sizeK/1024/1024;break;
           case 'M':
                  os<<sizeK/1024 ;break;
            case 'K':
                   os<<sizeK ; break;
            case       'T':
                os<<sizeK/1024/1024/1024; break;
            case 'S':   //扇区        
                  os<<p; break;
            case 'B':
                  os<<p*512; break;
//            case 'b':   //块
//                  size=$(($1*$blockSize))     ;;
//            case 'p'://   页
//                  size=$(($1*$pageSize))      ;;
            default:
                int sizeM = sizeK/1024;
                int sizeG = sizeK/1024/1024;
                int sizeT = sizeK/1024/1024/1024;
                if(sizeT >0) os << sizeT << "T";
                if(sizeG%1024 != 0 ) os << sizeG%1024 << "G";
                if(sizeM%1024 != 0 )  os << sizeM%1024 << "M";
                if(sizeK%1024 != 0 ) os << sizeK%1024 << "K";
                size = os.str();
                if(size.size()==0 )  size="0";
                return size;
        }
         size=os.str();
        return size;
    }
    
//1K to 2 ,1M to 2048 根据大小描述返回扇区个数
    long getCount(const char * str){
        char t=str[strlen(str)-1];
//        str[strlen(str)-1]='\0';
        long count=atoi(str);
        
        //单位[pbBSKMGT] 数量 进制[10,16,8,2] 重复操作的时候使用的标志位
        switch (t){
              case 'G':
                  count=count*2*1024*1024;   break;
              case 'M':
                  count=count*2*1024;   break;
             case 'K':
                  count=count*2;    break;
             
                  count=count*2*1024*1024*1024;     break;
            case 'B':   
                  count=count*512; break; 
             case 'S':
             default:
                 break;
          }

        return count;
   }

 
    void dumpPostionInfo(long p){
        cout << this->dev << "("<< this->getSize(this->size) << ") \t "
                <<p<<"/"<<this->size <<" \t " 
                <<   this->getSize(p)  << " \t " 
                << p*100/this->size <<"% \t " 
                <<endl;
    }
    
    bool sectorWriteto(string count,string fileName){
        cout << "wreite" << count << " > " <<fileName<<endl;
        long size=atoi(count.c_str());
        string fileData= this->get(postion,size);
//         file_put_content(fileName,fileData);    //文件大小过大
        FILE *fp;
        fp=fopen(fileName.c_str(),"wb");
        fwrite(fileData.c_str(),fileData.size(),1,fp);
        fclose(fp);
         return true;
    }
};
